#region Copyright RenGuiYou. All rights reserved.

//=====================================================
// NeatlyFrameWork
// Author:      RenGuiyou
// Feedback: 	mailto:750539605@qq.com
//=====================================================

#endregion

using System;
using System.Collections.Generic;
using Neatly.Module;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityEngine.Video;

namespace Neatly.UI
{
    public class YoutubeVideoFormat
    {
        public string format_id;
        public string url;
        public string ext;
        public int? width;
        public int? height;
        public int? fps;
        public string vcodec;
        public string acodec;
    }

    public class YoutubeVideoMetaData
    {
        public string title;
        public string url;
        public string ext;
        public YoutubeVideoFormat[] requested_formats;
        public YoutubeVideoFormat[] formats;
        public string _filename;
    }

    [DisallowMultipleComponent]
    [RequireComponent(typeof(VideoPlayer))]
    public sealed class NVideoImage : NMaskableGraphic
    {
        RenderTexture m_Texture;
        private Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
        private VideoPlayer m_VideoPlayer;
        private Action m_PrepareAction;
        private Action m_CompleteAction;
        private Action m_ErrorAction;
        private bool m_IsReady = false;

        private NVideoImage()
        {
            raycastTarget = false;
            useLegacyMeshGeneration = false;
        }

        private void SetReady(bool ready)
        {
            m_IsReady = ready;
            color = m_IsReady ? Color.white : Color.black;
            SetMaterialDirty();
        }

        protected override void Awake()
        {
            base.Awake();
            if (!Application.isPlaying) return;
            m_VideoPlayer = gameObject.GetComponent<VideoPlayer>();
            m_VideoPlayer.prepareCompleted += VideoPlayerPlay; //当视频准备好可以播放时的回调
            m_VideoPlayer.loopPointReached += VideoPlayerEnd; //当视频放到最后时的回调
            m_VideoPlayer.errorReceived += VideoPlayerError; //当视频播放出错时的回调
            m_VideoPlayer.seekCompleted += VideoPlayerSeek; //当视频定位回调
            SetReady(false);
        }

        protected override void OnEnable()
        {
            base.OnEnable();
            if (!Application.isPlaying) return;
            m_Texture = RenderTexture.GetTemporary((int) rectTransform.GetRectWidth(), (int) rectTransform.GetRectHeight(), 8);
            m_VideoPlayer.targetTexture = m_Texture;
        }

        protected override void OnDisable()
        {
            base.OnDisable();
            if (!Application.isPlaying) return;
            StopVideo();
            m_VideoPlayer.targetTexture = null;
            if (m_Texture == null) return;
            RenderTexture.ReleaseTemporary(m_Texture);
            m_Texture = null;
        }

        public override Texture mainTexture
        {
            get
            {
                if (m_IsReady) return m_Texture;
                return s_WhiteTexture;
            }
        }

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            Texture tex = mainTexture;
            vh.Clear();
            if (tex != null)
            {
                var r = GetPixelAdjustedRect();
                var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
                var scaleX = tex.width * tex.texelSize.x;
                var scaleY = tex.height * tex.texelSize.y;
                {
                    var color32 = color;
                    vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(m_UVRect.xMin * scaleX, m_UVRect.yMin * scaleY));
                    vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(m_UVRect.xMin * scaleX, m_UVRect.yMax * scaleY));
                    vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(m_UVRect.xMax * scaleX, m_UVRect.yMax * scaleY));
                    vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(m_UVRect.xMax * scaleX, m_UVRect.yMin * scaleY));
                    vh.AddTriangle(0, 1, 2);
                    vh.AddTriangle(2, 3, 0);
                }
            }
        }

        public void RegisterVideoAction(Action prepare, Action complete, Action error)
        {
            m_PrepareAction = prepare;
            m_CompleteAction = complete;
            m_ErrorAction = error;
        }

        #region 内置方法

        void VideoPlayerPlay(VideoPlayer vp)
        {
            m_PrepareAction?.Invoke();
        }

        void VideoPlayerEnd(VideoPlayer vp)
        {
            m_CompleteAction?.Invoke();
        }

        void VideoPlayerError(VideoPlayer vp, string desc)
        {
            m_ErrorAction?.Invoke();
            NDebug.LogError(desc);
        }

        private void VideoPlayerSeek(VideoPlayer vp)
        {
        }

        #endregion

        public void PrepareVideo(string url)
        {
            if (url.IndexOf("youtube.com") != -1)
            {
                RequestYoutubeUrl(url);
            }
            else
            {
                m_VideoPlayer.url = url;
                m_VideoPlayer.Prepare();
            }
        }

        public void PlayVideo()
        {
            m_VideoPlayer.Play();
            SetReady(true);
        }

        public void ReplayVideo()
        {
            m_VideoPlayer.Stop();
            m_VideoPlayer.Play();
            SetReady(true);
        }

        public void StopVideo()
        {
            m_VideoPlayer.Stop();
            SetReady(false);
        }

        public void PauseVideo()
        {
            m_VideoPlayer.Pause();
        }

        public void SetLoop(bool isLoop)
        {
            m_VideoPlayer.isLooping = isLoop;
        }

        public void Seek(float percent)
        {
            var count = m_VideoPlayer.frameCount;
            m_VideoPlayer.frame = (long) (count * percent);
        }

        public void SetVideoTime(float val)
        {
            m_VideoPlayer.time = val;
        }

        public double GetVideoTime()
        {
            return m_VideoPlayer.time;
        }

        public void SetVideoSpeed(float val)
        {
            m_VideoPlayer.playbackSpeed = val;
        }

        public float GetVideoSpeed()
        {
            return m_VideoPlayer.playbackSpeed;
        }

        public double GetVideoLength()
        {
            return m_VideoPlayer.length;
        }

        private static string ServerUrl = "https://unity-youtube-dl-server.herokuapp.com";

        private void RequestYoutubeUrl(string youtubeUrl)
        {
            var optionFlags = new List<string> {$"-f \"best\""};
            var requestUrl = $"{ServerUrl}/v1/video?url={youtubeUrl}";
            requestUrl += $"&options={UnityWebRequest.EscapeURL(string.Join(" ", optionFlags))}";
            var request = UnityWebRequest.Get(requestUrl);
            request.certificateHandler = new NewWebRequestCertificate();
            request.SendWebRequest().completed += operation =>
            {
                if (request.isNetworkError)
                {
                    return;
                }

                if (request.isHttpError)
                {
                    return;
                }

                var text = request.downloadHandler.text;
                var metaData = JsonUtility.FromJson<YoutubeVideoMetaData>(text);
                m_VideoPlayer.url = metaData.url;
                m_VideoPlayer.Prepare();
            };
        }
    }
}